#!/bin/bash
###############################################################################
#       脚本名称: test_framework.sh
#       功能描述: 测试框架基础工具，提供断言函数和测试运行器。
#       作者: 林再来
#       日期: 2025-10-13
#       版本: 1.0
#       功能:
#           1、断言函数（assert_equals, assert_true, assert_false等）
#           2、测试统计和报告
#           3、测试隔离和清理
#           4、彩色输出支持
###############################################################################

# 测试统计
TEST_TOTAL=0
TEST_PASSED=0
TEST_FAILED=0
TEST_SKIPPED=0

# 当前测试套件名称
CURRENT_TEST_SUITE=""

# 测试失败列表
declare -a FAILED_TESTS

# 颜色定义
if [[ -t 1 ]]; then
    COLOR_RED='\033[0;31m'
    COLOR_GREEN='\033[0;32m'
    COLOR_YELLOW='\033[1;33m'
    COLOR_BLUE='\033[0;34m'
    COLOR_RESET='\033[0m'
else
    COLOR_RED=''
    COLOR_GREEN=''
    COLOR_YELLOW=''
    COLOR_BLUE=''
    COLOR_RESET=''
fi

###############################################################################
# 测试框架核心函数
###############################################################################

# 函数: 开始测试套件
# 参数: $1 - 测试套件名称
function test_suite_start() {
    local suite_name="$1"
    CURRENT_TEST_SUITE="$suite_name"
    
    echo ""
    echo "========================================"
    echo "测试套件: $suite_name"
    echo "========================================"
}

# 函数: 结束测试套件
function test_suite_end() {
    echo ""
    echo "----------------------------------------"
    echo "测试套件 [$CURRENT_TEST_SUITE] 完成"
    echo "----------------------------------------"
}

# 函数: 运行测试
# 参数: $1 - 测试名称, $2 - 测试函数名
function run_test() {
    local test_name="$1"
    local test_func="$2"
    
    ((TEST_TOTAL++))
    
    echo -n "  测试: $test_name ... "
    
    # 执行测试函数
    local test_output
    local test_result
    
    test_output=$($test_func 2>&1)
    test_result=$?
    
    if [[ $test_result -eq 0 ]]; then
        echo -e "${COLOR_GREEN}✓ PASS${COLOR_RESET}"
        ((TEST_PASSED++))
    else
        echo -e "${COLOR_RED}✗ FAIL${COLOR_RESET}"
        if [[ -n "$test_output" ]]; then
            echo "    错误信息: $test_output"
        fi
        ((TEST_FAILED++))
        FAILED_TESTS+=("$CURRENT_TEST_SUITE::$test_name")
    fi
}

# 函数: 跳过测试
# 参数: $1 - 测试名称, $2 - 跳过原因
function skip_test() {
    local test_name="$1"
    local reason="${2:-未提供原因}"
    
    ((TEST_TOTAL++))
    ((TEST_SKIPPED++))
    
    echo -e "  测试: $test_name ... ${COLOR_YELLOW}⊝ SKIP${COLOR_RESET} ($reason)"
}

# 函数: 显示测试报告
function test_report() {
    echo ""
    echo "========================================"
    echo "测试报告"
    echo "========================================"
    echo "总计: $TEST_TOTAL"
    echo -e "${COLOR_GREEN}通过: $TEST_PASSED${COLOR_RESET}"
    echo -e "${COLOR_RED}失败: $TEST_FAILED${COLOR_RESET}"
    echo -e "${COLOR_YELLOW}跳过: $TEST_SKIPPED${COLOR_RESET}"
    
    if [[ $TEST_FAILED -gt 0 ]]; then
        echo ""
        echo "失败的测试:"
        for failed_test in "${FAILED_TESTS[@]}"; do
            echo -e "  ${COLOR_RED}✗${COLOR_RESET} $failed_test"
        done
    fi
    
    echo "========================================"
    
    # 返回失败数
    return $TEST_FAILED
}

###############################################################################
# 断言函数
###############################################################################

# 函数: 断言相等
# 参数: $1 - 期望值, $2 - 实际值, $3 - 错误消息(可选)
function assert_equals() {
    local expected="$1"
    local actual="$2"
    local message="${3:-断言失败: 期望 '$expected', 实际 '$actual'}"
    
    if [[ "$expected" != "$actual" ]]; then
        echo "$message" >&2
        return 1
    fi
    return 0
}

# 函数: 断言不相等
# 参数: $1 - 不期望的值, $2 - 实际值, $3 - 错误消息(可选)
function assert_not_equals() {
    local not_expected="$1"
    local actual="$2"
    local message="${3:-断言失败: 不应该等于 '$not_expected'}"
    
    if [[ "$not_expected" == "$actual" ]]; then
        echo "$message" >&2
        return 1
    fi
    return 0
}

# 函数: 断言为真
# 参数: $1 - 条件, $2 - 错误消息(可选)
function assert_true() {
    local condition="$1"
    local message="${2:-断言失败: 条件应该为真}"
    
    if [[ "$condition" != "true" ]] && [[ "$condition" != "0" ]]; then
        echo "$message" >&2
        return 1
    fi
    return 0
}

# 函数: 断言为假
# 参数: $1 - 条件, $2 - 错误消息(可选)
function assert_false() {
    local condition="$1"
    local message="${2:-断言失败: 条件应该为假}"
    
    if [[ "$condition" == "true" ]] || [[ "$condition" == "0" ]]; then
        echo "$message" >&2
        return 1
    fi
    return 0
}

# 函数: 断言为空
# 参数: $1 - 值, $2 - 错误消息(可选)
function assert_empty() {
    local value="$1"
    local message="${2:-断言失败: 值应该为空}"
    
    if [[ -n "$value" ]]; then
        echo "$message (实际值: '$value')" >&2
        return 1
    fi
    return 0
}

# 函数: 断言不为空
# 参数: $1 - 值, $2 - 错误消息(可选)
function assert_not_empty() {
    local value="$1"
    local message="${2:-断言失败: 值不应该为空}"
    
    if [[ -z "$value" ]]; then
        echo "$message" >&2
        return 1
    fi
    return 0
}

# 函数: 断言包含
# 参数: $1 - 字符串, $2 - 子串, $3 - 错误消息(可选)
function assert_contains() {
    local string="$1"
    local substring="$2"
    local message="${3:-断言失败: '$string' 应该包含 '$substring'}"
    
    if [[ "$string" != *"$substring"* ]]; then
        echo "$message" >&2
        return 1
    fi
    return 0
}

# 函数: 断言不包含
# 参数: $1 - 字符串, $2 - 子串, $3 - 错误消息(可选)
function assert_not_contains() {
    local string="$1"
    local substring="$2"
    local message="${3:-断言失败: '$string' 不应该包含 '$substring'}"
    
    if [[ "$string" == *"$substring"* ]]; then
        echo "$message" >&2
        return 1
    fi
    return 0
}

# 函数: 断言文件存在
# 参数: $1 - 文件路径, $2 - 错误消息(可选)
function assert_file_exists() {
    local file="$1"
    local message="${2:-断言失败: 文件 '$file' 应该存在}"
    
    if [[ ! -f "$file" ]]; then
        echo "$message" >&2
        return 1
    fi
    return 0
}

# 函数: 断言文件不存在
# 参数: $1 - 文件路径, $2 - 错误消息(可选)
function assert_file_not_exists() {
    local file="$1"
    local message="${2:-断言失败: 文件 '$file' 不应该存在}"
    
    if [[ -f "$file" ]]; then
        echo "$message" >&2
        return 1
    fi
    return 0
}

# 函数: 断言目录存在
# 参数: $1 - 目录路径, $2 - 错误消息(可选)
function assert_dir_exists() {
    local dir="$1"
    local message="${2:-断言失败: 目录 '$dir' 应该存在}"
    
    if [[ ! -d "$dir" ]]; then
        echo "$message" >&2
        return 1
    fi
    return 0
}

# 函数: 断言命令成功
# 参数: $@ - 命令和参数
function assert_success() {
    local output
    local exit_code
    
    output=$("$@" 2>&1)
    exit_code=$?
    
    if [[ $exit_code -ne 0 ]]; then
        echo "断言失败: 命令应该成功执行: $*" >&2
        echo "退出码: $exit_code" >&2
        echo "输出: $output" >&2
        return 1
    fi
    return 0
}

# 函数: 断言命令失败
# 参数: $@ - 命令和参数
function assert_failure() {
    local output
    local exit_code
    
    output=$("$@" 2>&1)
    exit_code=$?
    
    if [[ $exit_code -eq 0 ]]; then
        echo "断言失败: 命令应该失败: $*" >&2
        echo "输出: $output" >&2
        return 1
    fi
    return 0
}

# 函数: 断言匹配正则表达式
# 参数: $1 - 字符串, $2 - 正则表达式, $3 - 错误消息(可选)
function assert_matches() {
    local string="$1"
    local pattern="$2"
    local message="${3:-断言失败: '$string' 应该匹配正则 '$pattern'}"
    
    if [[ ! "$string" =~ $pattern ]]; then
        echo "$message" >&2
        return 1
    fi
    return 0
}

###############################################################################
# 测试辅助函数
###############################################################################

# 函数: 创建临时测试目录
# 返回: 临时目录路径
function create_test_dir() {
    local test_dir
    test_dir=$(mktemp -d "${TMPDIR:-/tmp}/test_config_XXXXXX")
    echo "$test_dir"
}

# 函数: 清理测试目录
# 参数: $1 - 测试目录路径
function cleanup_test_dir() {
    local test_dir="$1"
    
    if [[ -n "$test_dir" ]] && [[ -d "$test_dir" ]]; then
        rm -rf "$test_dir"
    fi
}

# 函数: 创建测试文件
# 参数: $1 - 文件路径, $2 - 文件内容
function create_test_file() {
    local file="$1"
    local content="$2"
    
    echo "$content" > "$file"
}

# 函数: 比较文件内容
# 参数: $1 - 文件1, $2 - 文件2
function files_equal() {
    local file1="$1"
    local file2="$2"
    
    if [[ ! -f "$file1" ]] || [[ ! -f "$file2" ]]; then
        return 1
    fi
    
    diff -q "$file1" "$file2" >/dev/null 2>&1
    return $?
}

###############################################################################
# 简单日志函数（用于测试输出）
###############################################################################

function log_debug() {
    local module="${1:-}"
    shift
    echo "[DEBUG] [$module] $*" >&2
}

function log_info() {
    local module="${1:-}"
    shift
    echo "[INFO]  [$module] $*" >&2
}

function log_warn() {
    local module="${1:-}"
    shift
    echo "[WARN]  [$module] $*" >&2
}

function log_error() {
    local module="${1:-}"
    shift
    echo "[ERROR] [$module] $*" >&2
}

# 函数: 打印测试摘要
function print_test_summary() {
    test_report
}

# 函数: 根据测试结果退出
function exit_with_test_result() {
    if [[ $TEST_FAILED -gt 0 ]]; then
        exit 1
    else
        exit 0
    fi
}

